/*
 * Camera.cpp
 *
 *  Created on: 04.06.2011
 *      Author: kirill
 *      Copyright: LGPL
 */

#include "Camera.h"
#include "../Constants.h"

CGameCamera::CGameCamera() :  //TODO Remove hardcoded values
	eye(-0.6f, -0.6f, -2.0f), center(0.0f, 0.0f, 0.0f), up(1.0f, 0.0f, 0.0f)
{
	currentGameCamera.leftTopX = 0;
	currentGameCamera.leftTopX = 0;
	currentGameCamera.projectionMatrix = glm::perspective(45.0f, 4.0f / 3.0f, 0.1f, 100.0f);
	currentGameCamera.height = 1.0;
	currentGameCamera.width  = 1.0;
	//currentGameCamera.visualParams = {0};
	currentGameCamera.viewMatrix = glm::lookAt( eye, center, up );
	CalculateClipPlanes( currentGameCamera.frustum, (currentGameCamera.viewMatrix * currentGameCamera.projectionMatrix) );
	currentGameCamera.sphere = CalculateClipSphere( eye, 0.1f, 100.0f, 45.0f );
}

vec3
CGameCamera::RotateAroundPoint( vec3 Obj, vec3 Point, const float angelX, const float angelY, const float angelZ  )
{
	vec3 tmpVec = Obj - Point;

	tmpVec = glm::gtx::rotate_vector::rotate( tmpVec, angelX , glm::vec3(1.0f, 0.0f, 0.0f) );
	tmpVec = glm::gtx::rotate_vector::rotate( tmpVec, angelY , glm::vec3(0.0f, 1.0f, 0.0f) );
	tmpVec = glm::gtx::rotate_vector::rotate( tmpVec, angelZ , glm::vec3(0.0f, 0.0f, 1.0f) );

	tmpVec += Point;
	return tmpVec;
}

void
CGameCamera::Translate( const float dx, const float dy, const float dz )
{
	vec3 tmpVec = glm::vec3(dx, dy, dz);
	eye += tmpVec;
	center += tmpVec;
	currentGameCamera.viewMatrix = glm::lookAt( eye, center, up );
	CalculateClipPlanes( currentGameCamera.frustum, (currentGameCamera.viewMatrix * currentGameCamera.projectionMatrix) );
}

void
CGameCamera::RotateEyeAroundCenter( const float angelX, const float angelY, const float angelZ )
{
	eye = RotateAroundPoint( eye, center, angelX, angelY, angelZ );
	currentGameCamera.viewMatrix = glm::lookAt( eye, center, up );
	CalculateClipPlanes( currentGameCamera.frustum, (currentGameCamera.viewMatrix * currentGameCamera.projectionMatrix) );
}

void
CGameCamera::RotateCenterAroundEye( const float angelX, const float angelY, const float angelZ )
{
	center = RotateAroundPoint( center, eye, angelX, angelY, angelZ );
	currentGameCamera.viewMatrix = glm::lookAt( eye, center, up );
	CalculateClipPlanes( currentGameCamera.frustum, (currentGameCamera.viewMatrix * currentGameCamera.projectionMatrix) );
}

void
CGameCamera::CalculateClipPlanes( glm::vec4 *Frustum, const glm::mat4 &ViewProjMatrix )
{
   // ViewProjMatrix[5] - ViewProjMatrix[7]; //FIXME Это похоже на жёсткий баг

    Frustum[LEFT_CLIP_PLANE].x = ViewProjMatrix[0].w + ViewProjMatrix[0].x;
    Frustum[LEFT_CLIP_PLANE].y = ViewProjMatrix[1].w + ViewProjMatrix[1].x;
    Frustum[LEFT_CLIP_PLANE].z = ViewProjMatrix[2].w + ViewProjMatrix[2].x;
    Frustum[LEFT_CLIP_PLANE].w = ViewProjMatrix[3].w + ViewProjMatrix[3].x;

    Frustum[RIGHT_CLIP_PLANE].x = ViewProjMatrix[0].w - ViewProjMatrix[0].x;
    Frustum[RIGHT_CLIP_PLANE].y = ViewProjMatrix[1].w - ViewProjMatrix[1].x;
    Frustum[RIGHT_CLIP_PLANE].z = ViewProjMatrix[2].w - ViewProjMatrix[2].x;
    Frustum[RIGHT_CLIP_PLANE].w = ViewProjMatrix[3].w - ViewProjMatrix[3].x;

    Frustum[BUTTON_CLIP_PLANE].x = ViewProjMatrix[0].y + ViewProjMatrix[0].w;
    Frustum[BUTTON_CLIP_PLANE].y = ViewProjMatrix[1].y + ViewProjMatrix[1].w;
    Frustum[BUTTON_CLIP_PLANE].z = ViewProjMatrix[2].y + ViewProjMatrix[2].w;
    Frustum[BUTTON_CLIP_PLANE].w = ViewProjMatrix[3].y + ViewProjMatrix[3].w;

    Frustum[TOP_CLIP_PLANE].x = ViewProjMatrix[0].w - ViewProjMatrix[0].y;
    Frustum[TOP_CLIP_PLANE].y = ViewProjMatrix[1].w - ViewProjMatrix[1].y;
	Frustum[TOP_CLIP_PLANE].z = ViewProjMatrix[2].w - ViewProjMatrix[2].y;
	Frustum[TOP_CLIP_PLANE].w = ViewProjMatrix[3].w - ViewProjMatrix[3].y;

	Frustum[FAR_CLIP_PLANE].x = ViewProjMatrix[0].z;
	Frustum[FAR_CLIP_PLANE].y = ViewProjMatrix[1].z;
	Frustum[FAR_CLIP_PLANE].w = ViewProjMatrix[2].z;

	Frustum[NEAR_CLIP_PLANE].x = ViewProjMatrix[0].w - ViewProjMatrix[0].z;
	Frustum[NEAR_CLIP_PLANE].y = ViewProjMatrix[1].w - ViewProjMatrix[1].z;
	Frustum[NEAR_CLIP_PLANE].z = ViewProjMatrix[2].w - ViewProjMatrix[2].z;
	Frustum[NEAR_CLIP_PLANE].w = ViewProjMatrix[3].w - ViewProjMatrix[3].z;
}

glm::vec4
CGameCamera::CalculateClipSphere( const glm::vec3 &LookAt, const float ZNear, const float ZFar,const float Fovy )
{
	float Length = ZFar-ZNear;
	float Height = Length * tan( Fovy / 2 );
	glm::vec3 SphereCenter( 0.0f, 0.0f, ZNear - (Length / 2) + LookAt.z ); //TODO Проверить корректность всех вычислений
	glm::vec3 FarCorner( Height, Height, ( Length - (SphereCenter.z / 2) ) );

	glm::vec4 Result( SphereCenter, FarCorner.length() );

	return Result;
}
